/*
 * Copyright (C) 2016 Nishant Srivastava
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package github.nisrulz.easydeviceinfo.base;

import ohos.aafwk.ability.SystemMemoryInfo;
import ohos.app.Context;
import ohos.data.usage.DataUsage;
import ohos.data.usage.MountState;
import ohos.data.usage.StatVfs;
import ohos.hiviewdfx.HiLog;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import github.nisrulz.easydeviceinfo.common.EasyDeviceInfo;

/**
 * EasyMemory Mod Class
 * <p>
 * Deprecation warning suppressed since it is handled in the code
 *
 * @since 2021-06-10
 */
@SuppressWarnings("deprecation")
public class EasyMemoryMod {
    private static final String IO_EXCEPTION = "IO Exception";
    private static final int BYTEFACTOR = 1024;
    private final Context context;

    /**
     * Instantiates a new Easy memory mod.
     *
     * @param context the context
     */
    public EasyMemoryMod(final Context context) {
        this.context = context;
    }

    /**
     * Gets total ram.
     *
     * @return the total ram
     */
    public final long getTotalRAM() {
        long totalMemory = 0;
        if (context.getAbilityManager() != null) {
            SystemMemoryInfo systemMemoryInfo = new SystemMemoryInfo();
            context.getAbilityManager().getSystemMemoryInfo(systemMemoryInfo);
            totalMemory = systemMemoryInfo.getTotalSysMem();
        } else {
            RandomAccessFile reader = null;
            String load;
            try {
                reader = new RandomAccessFile("/proc/meminfo", "r");
                load = reader.readLine().replaceAll("\\D+", "");
                totalMemory = (long) Integer.parseInt(load);
            } catch (IOException e) {
                if (EasyDeviceInfo.debuggable) {
                    HiLog.error(EasyDeviceInfo.LABEL, "", IO_EXCEPTION + e);
                }
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        if (EasyDeviceInfo.debuggable) {
                            HiLog.error(EasyDeviceInfo.LABEL, "", IO_EXCEPTION + e);
                        }
                    }
                }
            }
        }
        return totalMemory;
    }

    /**
     * Gets available internal memory size.
     *
     * @return the available internal memory size
     */
    public final long getAvailableInternalMemorySize() {
        File path = getDataDirectory();
        StatVfs statVfs = new StatVfs(path.getPath());
        return statVfs.getAvailableSpace();
    }

    /**
     * Gets total internal memory size.
     *
     * @return the total internal memory size
     */
    public final long getTotalInternalMemorySize() {
        File path = getDataDirectory();
        StatVfs statVfs = new StatVfs(path.getPath());
        return statVfs.getSpace();
    }

    /**
     * Gets available external memory size.
     *
     * @return the available external memory size
     */
    public final long getAvailableExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = getExternalStorageDirectory();
            StatVfs statVfs = new StatVfs(path.getPath());
            return statVfs.getAvailableSpace();
        } else {
            return 0;
        }
    }

    private boolean externalMemoryAvailable() {
        return DataUsage.getDiskMountedStatus().equals(MountState.DISK_MOUNTED);
    }

    /**
     * Gets total external memory size.
     *
     * @return the total external memory size
     */
    public final long getTotalExternalMemorySize() {
        if (externalMemoryAvailable()) {
            File path = getExternalStorageDirectory();
            StatVfs statVfs = new StatVfs(path.getPath());
            return statVfs.getSpace();
        } else {
            return 0;
        }
    }

    private File getExternalStorageDirectory() {
        File file = context.getExternalCacheDir().getParentFile();
        while (file != null) {
            if (!file.getPath().contains("Android")) {
                break;
            }
            file = file.getParentFile();
        }
        return file;
    }

    private File getDataDirectory() {
        File file = context.getDataDir().getParentFile();
        while (file != null) {
            if (!file.getPath().contains("user")) {
                break;
            }
            file = file.getParentFile();
        }
        return file;
    }

    /**
     * Convert to kb float.
     *
     * @param valInBytes the val in bytes
     * @return the float
     */
    public float convertToKb(long valInBytes) {
        return (float) valInBytes / BYTEFACTOR;
    }

    /**
     * Convert to mb float.
     *
     * @param valInBytes the val in bytes
     * @return the float
     */
    public float convertToMb(long valInBytes) {
        return (float) valInBytes / (BYTEFACTOR * BYTEFACTOR);
    }

    /**
     * Convert to gb float.
     *
     * @param valInBytes the val in bytes
     * @return the float
     */
    public float convertToGb(long valInBytes) {
        return (float) valInBytes / (BYTEFACTOR * BYTEFACTOR * BYTEFACTOR);
    }

    /**
     * Convert to tb float.
     *
     * @param valInBytes the val in bytes
     * @return the float
     */
    @SuppressWarnings("NumericOverflow")
    public float convertToTb(long valInBytes) {
        return (float) valInBytes / (BYTEFACTOR * BYTEFACTOR * BYTEFACTOR * BYTEFACTOR);
    }
}
